/*
 * PointToLocationQuery.cpp
 *
 *  Created on: Dec 7, 2009
 *      Author: jbarreneche
 */

#include "PointToLocationQuery.h"

Route* pickBetter(Route* oneRoute, Route* otherRoute);
PointToLocationQuery::PointToLocationQuery(Map *map, string originRoadName, int originHeight, MapLocationType type,
		RouteOptimize optimizationStrategy)  throw(UnexistingAddressException, RoadNotFoundException) :
QueryRoute(map, originRoadName, originHeight, optimizationStrategy), type(type) {

	LinkedList<MapLocation>::Iterator it = map->getMapLocations(this->type).iterator();
	while (it.hasNext()) {
		MapLocation* location = it.next();
		locationAddresses.add(0, new MapAddress(this->queriedMap->createDestinationAddress(location->getRoadName(), location->getHeight())));
	}
	safeCalculateRoute();
}
PointToLocationQuery::~PointToLocationQuery() {
	while (!locationAddresses.isEmpty()) {
		delete locationAddresses.removeFirst();
	}
}
void delete_if_not_null(Route* route) {
	if (route != NULL) delete route;
}
void PointToLocationQuery::recalculateRoute() {
	Route* betterRoute = NULL;
	Route* previousRoute = NULL;
	LinkedList<MapAddress>::Iterator it = locationAddresses.iterator();
	while (it.hasNext()) {
		try {
			Route* route = queriedMap->route(currentOrigin, *it.next(), optimizationStrategy);
			betterRoute = pickBetter(route, betterRoute);
			delete_if_not_null(route == betterRoute? previousRoute : route);
			previousRoute = betterRoute;
		} catch (OutOfReachException oore) { }
	}
	if (betterRoute == NULL)  throw OutOfReachException();

	this->setRemainingRoute(betterRoute);
}

Route* pickBetter(Route* oneRoute, Route* otherRoute) {
	if (oneRoute == NULL) return otherRoute;
	if (otherRoute == NULL) return oneRoute;
	return (oneRoute->travelCost() < otherRoute->travelCost())? oneRoute : otherRoute;
}
util::LinkedList<MapPoint> PointToLocationQuery::finishPoints() {
	util::LinkedList<MapPoint> lista;
	util::LinkedList<MapAddress>::Iterator addresses = this->locationAddresses.iterator();
	while (addresses.hasNext()) {
		lista.add(0, addresses.next());
	}
	return lista;
}
